package lion.dev.lang;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;

/**
 * 以对象的某个字段来比较对象的大小，这通常对一个集合中的对象进行排序十分有用<br/>
 * 字段值比较时自动区分日期，数组，集合，数字类型，其他的通过字段值原生方式来比较.
 *
 * @author lion
 * @date 2011-5-26
 */
public class ObjectComparator implements Comparator<Object> {

	Field field;
	boolean reverse = false;

	public ObjectComparator(Class<?> clz, String field, boolean reverse) throws NoSuchFieldException {

		super();
		try {
			this.field = clz.getDeclaredField(field);
			this.field.setAccessible(true);
		} catch (SecurityException e) {
		} catch (NoSuchFieldException e) {
			throw e;
		}

		this.reverse = reverse;
	}

	@Override
	public int compare(Object o1, Object o2) {

		if (Date.class.isAssignableFrom(field.getType())) {

			Date d1 = null;
			Date d2 = null;

			try {
				d1 = (field.get(o1) == null ? new Date(0) : (Date) field.get(o1));
				d2 = (field.get(o2) == null ? new Date(0) : (Date) field.get(o2));
			} catch (Exception ex) {
				return -1;
			}

			return reverse ? d2.compareTo(d1) : d1.compareTo(d2);
		} else if (field.getType().isArray()) {
			Object a = null;
			Object b = null;

			try {
				a = field.get(o1);
				b = field.get(o2);
			} catch (Exception ex) {
			}

			int aLength = a != null ? Array.getLength(a) : -1;
			int bLength = b != null ? Array.getLength(b) : -1;

			if (reverse) {
				return bLength - aLength;
			} else {
				return aLength - bLength;
			}
		} else if (Collection.class.isAssignableFrom(field.getType())) {
			Collection<?> lst1 = null;
			Collection<?> lst2 = null;

			try {
				lst1 = (Collection<?>) field.get(o1);
				lst2 = (Collection<?>) field.get(o2);
			} catch (Exception e) {
			}

			int a = -1;
			int b = -1;
			if (lst1 != null) {
				a = lst1.size();
			}
			if (lst2 != null) {
				b = lst2.size();
			}

			if (reverse) { return b - a; }
			return a - b;

		} else if (Number.class.isAssignableFrom(field.getType())) {
			Number i1 = 0;
			Number i2 = 0;

			try {
				i1 = (Number) field.get(o1);
				i2 = (Number) field.get(o2);
			} catch (Exception ex) {
			}
			double v1 = i1.doubleValue();
			double v2 = i2.doubleValue();
			if (reverse) {
				if (v2 > v1) {
					return 1;
				} else if (v2 < v1) {
					return -1;
				} else {
					return 1;
				}
			} else {
				if (v1 > v2) {
					return 1;
				} else if (v1 < v2) {
					return -1;
				} else {
					return 1;
				}
			}
		} else {
			Object o1_1 = null;
			Object o2_1 = null;
			try {
				o1_1 = field.get(o1);
				o2_1 = field.get(o2);
			} catch (Exception ex) {
			}

			int a = -1;
			int b = -1;
			if (o1_1 != null) {
				a = o1_1.toString().length();
			}
			if (o2_1 != null) {
				b = o2_1.toString().length();
			}
			if (reverse) { return b - a; }
			return a - b;
		}
	}
}